// SPDX-License-Identifier: GPL-2.0-or-later

/////////////////////////////////////////////////////////////////
//TODO: This class has too many overlap with MDI Area.
//It should inherit the QMdiArea...
/////////////////////////////////////////////////////////////////

#include <stdio.h>

#include <QApplication>
#include <QEvent>
#include <QKeyEvent>
#include <QIcon>
#include <QKeySequence>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QTabBar>
#include <QMouseEvent>
#include <QMenu>
#include <QMessageBox>
#include <QToolButton>

#include "fqterm_frame.h"
#include "fqterm_path.h"
#include "fqterm_trace.h"
#include "fqterm_window.h"
#include "fqterm_wndmgr.h"

namespace FQTerm {

//constructor
FQTermWndMgr::FQTermWndMgr(QWidget *parent, const char *name)
    : QMdiArea(parent),
      subWindowSize_(640, 480),
      subWindowMax_(true),
      tabBar_( nullptr )
{
    tabBar_ = new FQTermTabBar(this);
    tabBar_->setShape(QTabBar::RoundedSouth);
    FQ_VERIFY(connect(tabBar_, SIGNAL(currentChanged(int)),  this, SLOT(activateTheWindow(int))));
    FQ_VERIFY(connect(tabBar_, SIGNAL(rightClicked(int,const QPoint&)), this, SLOT(onTabRightClicked(int,const QPoint&))));
    FQ_VERIFY(connect(tabBar_, SIGNAL(doubleClicked(int,const QPoint&)), this, SLOT(onTabDoubleClicked(int,const QPoint&))));

    setObjectName(name);
    termFrame_ = (FQTermFrame*)parent;
    isAfterRemoved_ = false;

    setViewMode( QMdiArea::TabbedView );
    setTabsClosable( true );
    setTabPosition( QTabWidget::North );
    setTabShape(QTabWidget::Triangular);
}


FQTermWndMgr::~FQTermWndMgr(){}


//remove window-tab-iconset
bool FQTermWndMgr::closeWindow(FQTermWindow *mw)
{
    FQ_FUNC_TRACE("wndmgr", 3);
    QMdiSubWindow* subWindow = FQToMDI(mw);
    if (subWindow) {
        return subWindow->close();
    }
    return false;
}

bool FQTermWndMgr::closeAllWindow() {
    FQ_FUNC_TRACE("wndmgr", 3);

    bool anyConnected = false;

    for (int i = 0; i < subWindowList().size(); ++i) {
        FQTermWindow * window = (FQTermWindow *)(subWindowList()[i]->widget());
        if (window->isConnected()) {
            anyConnected = true;
            break;
        }
    }

    bool warn = FQTermPref::getInstance()->openWarnOnClose_;
    if (anyConnected && warn) {
	QMessageBox mb(tr("vTerminal"),
                       tr("Still connected, do you really want to exit?"),
                       QMessageBox::Warning, QMessageBox::Yes|QMessageBox::Default,
                       QMessageBox::No | QMessageBox::Escape, 0, this);
        if (mb.exec() != QMessageBox::Yes) {
            return false;
        }
    }
    FQTermPref::getInstance()->openWarnOnClose_ = false;
    while (count() > 0) {
        bool closed = subWindowList().at(0)->close();
        if (!closed) {
            FQTermPref::getInstance()->openWarnOnClose_ = warn;
            return false;
        }
    }
    FQTermPref::getInstance()->openWarnOnClose_ = warn;
    return true;
}



//active the window when switch the tab
void FQTermWndMgr::activateTheWindow(int n) {
    FQ_FUNC_TRACE("wndmgr", 3);

    if (n < 0 || n >= count() || subWindowList().at(n) == activeSubWindow())
        return;

    QMdiSubWindow *subWindow = subWindowList().at(n);

    // Fix the refresh bug by send PaintEvent to session screen.
    //subWindow->setFocus();
    setActiveSubWindow(subWindow);

}

//blink the tab when message come in
void FQTermWndMgr::blinkTheTab(FQTermWindow *mw, bool bVisible)
{
    FQ_FUNC_TRACE("wndmgr", 10);
    static QIcon a_icon(getPath(RESOURCE) + "pic/tabpad.png");
    static QIcon b_icon(getPath(RESOURCE) + "pic/transp.png");

    //find where it is
    QMdiSubWindow* subWindow = FQToMDI(mw);
    if (!subWindow)
        return;
    int n = subWindowList().indexOf(subWindow);
    QIcon *icon = icons_.at(n);
    //FIXME: QIcon::Automatic
    if (bVisible) {
        icon->addFile(getPath(RESOURCE) + "pic/tabpad.png");

        tabBar_->setTabIcon(n, a_icon);
    } else {
        //,QIcon::Automatic);
        icon->addFile(getPath(RESOURCE) + "pic/transp.png");
        tabBar_->setTabIcon(n, b_icon);
    }
    //,QIcon::Automatic);


    tabBar_->update();
}

//return the number of connected window
int FQTermWndMgr::count() {
    return subWindowList().count();
}

FQTermWindow *FQTermWndMgr::activeWindow() {
    return MDIToFQ(activeSubWindow());
}


bool FQTermWndMgr::afterRemove() {
    if (isAfterRemoved_) {
        isAfterRemoved_ = false;
        return true;
    } else {
        return false;
    }
}

void FQTermWndMgr::refreshAllExcept(FQTermWindow *termWindow) {
    for (int i = 0; i < subWindowList().count(); ++i) {
        FQTermWindow * window = (FQTermWindow *)(subWindowList()[i]->widget());
        if (window != termWindow) {
            window->repaintScreen();
        }
    }
}


FQTermWindow* FQTermWndMgr::newWindow( const FQTermParam &param, FQTermConfig* config, QIcon* icon, int index /*= -1*/ )
{
    FQTermWindow *window = new FQTermWindow(config, termFrame_, param, index, this, 0);
    //add window-tab-icon to window manager


    QMdiSubWindow* subWindow = addSubWindow(window);
    subWindow->setAttribute(Qt::WA_OpaquePaintEvent);
    subWindow->setAttribute(Qt::WA_DeleteOnClose);

    icons_.append(icon);
    if (count() == 1) {
        termFrame_->enableMenuToolBar(true);
    }
    //if no this call, the tab won't display until you resize the window
    int idx = tabBar_->addTab(*icon, window->windowTitle());
    tabBar_->updateGeometry();
    tabBar_->update();

    subWindow->resize(subWindowSize_);
    if (subWindowMax_) {
        subWindow->setWindowFlags(Qt::SubWindow | Qt::CustomizeWindowHint | Qt::WindowMinMaxButtonsHint);
        subWindow->showMaximized();
    } else {
        subWindow->setWindowFlags(Qt::SubWindow | (Qt::CustomizeWindowHint
                                                   | Qt::WindowMinMaxButtonsHint
                                                   | Qt::WindowSystemMenuHint));
        subWindow->show();
    }
    tabBar_->setTabData(idx, QVariant::fromValue((QObject*)window));
    FQ_VERIFY(connect(window, SIGNAL(destroyed(QObject*)), this ,SLOT(onSubWindowClosed(QObject*))));
    FQ_VERIFY(connect(window, SIGNAL(resizeSignal(FQTermWindow*)), this, SLOT(subWindowResized(FQTermWindow*))));
    FQ_VERIFY(connect(this, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(onSubWindowActivated(QMdiSubWindow*))));
    FQ_VERIFY(connect(window, SIGNAL(blinkTheTab(FQTermWindow*, bool)), this, SLOT(blinkTheTab(FQTermWindow*, bool))));
    FQ_VERIFY(connect(window, SIGNAL(refreshOthers(FQTermWindow*)), this, SLOT(refreshAllExcept(FQTermWindow*))));
    FQ_VERIFY(connect(window, SIGNAL(connectionClosed(FQTermWindow*)),this, SLOT(closeWindow(FQTermWindow*)), Qt::QueuedConnection));
    return window;
}

void FQTermWndMgr::onSubWindowClosed(QObject* obj) {

    for (int i = 0; i < tabBar_->count(); ++i) {
        if (tabBar_->tabData(i) == QVariant::fromValue(obj)) {
            if (count() == 0) {
                termFrame_->enableMenuToolBar(false);
            }
            if (i == tabBar_->currentIndex())
                isAfterRemoved_ = true;
            tabBar_->removeTab(i);
            icons_.removeAt(i);
        }
    }

}

//---------------------------
//record subwindows' size 
//---------------------------
void FQTermWndMgr::subWindowResized(FQTermWindow *mw) {
    QMdiSubWindow* subWindow = FQToMDI(mw);
    if (!subWindow)
        return;
    Qt::WindowFlags wfs = subWindow->windowFlags();

    if (!(subWindowMax_ = subWindow->isMaximized())){
        if (!subWindow->isMinimized()) {
            subWindowSize_ = subWindow->frameSize();
        }
        subWindow->setWindowFlags(wfs | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
    }
    else {
        subWindow->setWindowFlags(wfs & ~Qt::WindowSystemMenuHint);
    }

}

void FQTermWndMgr::cascade() {
    QSize oldSize = subWindowSize_;
    cascadeSubWindows();
    foreach(QMdiSubWindow* subWindow, subWindowList()) {
        if (subWindow) {
            subWindow->resize(oldSize);
        }
    }
}

void FQTermWndMgr::tile()
{
    tileSubWindows();
}

void FQTermWndMgr::activateNextWindow() {
    activateTheWindow((activeWindowIndex() + 1) % count());
}

void FQTermWndMgr::activatePrevWindow() {
    activateTheWindow((activeWindowIndex() - 1 + count()) % count());
}

FQTermWindow * FQTermWndMgr::nthWindow(int n)
{
    return (FQTermWindow *)(subWindowList()[n]->widget());
}

void FQTermWndMgr::onSubWindowActivated(QMdiSubWindow * subWindow) {
    int n = subWindowList().indexOf(subWindow);
    if (n == -1)
        return;
    FQTermWindow* mw = MDIToFQ(subWindow);
    if (mw->isMaximized() && afterRemove()) {
        mw->showNormal();
        mw->showMaximized();
    }
    if (tabBar_->currentIndex() != n) {
        FQ_VERIFY(disconnect(this, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(onSubWindowActivated(QMdiSubWindow*))));
        tabBar_->setCurrentIndex(n);
        FQ_VERIFY(connect(this, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(onSubWindowActivated(QMdiSubWindow*))));
    }
    termFrame_->updateMenuToolBar();
}

void FQTermWndMgr::onTabRightClicked(int index, const QPoint& p) {
    QMenu* menu = FQToMDI(nthWindow(index))->systemMenu();
    menu->popup(p);
}

void FQTermWndMgr::onTabDoubleClicked(int index, const QPoint& p) {
    closeWindow(nthWindow(index));
}

FQTermWindow* FQTermWndMgr::MDIToFQ( QMdiSubWindow* subWindow )
{
    if (!subWindowList().contains(subWindow))
        return NULL;
    return (FQTermWindow*)subWindow->widget();
}

QMdiSubWindow* FQTermWndMgr::FQToMDI( FQTermWindow* window )
{
    for (int i = 0; i < subWindowList().count(); ++i) {
        if ((FQTermWindow*)(subWindowList()[i]->widget()) == window) {
            return subWindowList()[i];
        }
    }
    return NULL;
}

int FQTermWndMgr::FQToIndex( FQTermWindow* window )
{
    return subWindowList().indexOf(FQToMDI(window));
}

bool FQTermWndMgr::event( QEvent* e ) {
    if (e->type() == QEvent::ShortcutOverride) {
        QKeyEvent* ke = (QKeyEvent*)e;
        if (ke->key() == Qt::Key_W && ke->modifiers() == Qt::ControlModifier) {
            ke->accept();
            return true;
        }
    }
    return QMdiArea::event(e);
}
void FQTermTabBar::mouseReleaseEvent( QMouseEvent * me ) {
    int index = tabAt(me->pos());
    if (index != -1 && me->button() == Qt::RightButton && me->modifiers() == Qt::NoModifier) {
        emit rightClicked(index, mapToGlobal(me->pos()));
    }
}

void FQTermTabBar::mouseDoubleClickEvent( QMouseEvent * me ) {
    int index = tabAt(me->pos());
    if (index != -1 && me->button() == Qt::LeftButton && me->modifiers() == Qt::NoModifier) {
        emit doubleClicked(index, mapToGlobal(me->pos()));
    }
}
}  // namespace FQTerm

//#include "fqterm_wndmgr.moc"
